package com.talkyun.openx.client.conn;

import javax.net.ssl.*;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;

import static java.net.Proxy.Type.HTTP;
import static java.util.Base64.getEncoder;

public class BaseConnection {

    private static class TrustAnyTrustManager implements X509TrustManager {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) {
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[]{};
        }
    }

    private static class TrustAnyHostnameVerifier implements HostnameVerifier {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }

    protected String url;
    protected int timeout;
    protected boolean keepAlive;

    private String httpProxyAddress;       // host:port
    private String httpProxyAuthorization; // username:password (base64)

    public BaseConnection(String url) {
        this(url, 3000, true);
    }

    public BaseConnection(String url, int timeout, boolean keepAlive) {
        this.url = url;
        this.timeout = timeout;
        this.keepAlive = keepAlive;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public void setHttpProxyAddress(String httpProxyAddress) {
        this.httpProxyAddress = httpProxyAddress;
    }

    public void setHttpProxyAuthorization(String httpProxyAuthorization) {
        this.httpProxyAuthorization = "Basic " + new String(getEncoder().encode(httpProxyAuthorization.getBytes()));
    }

    protected HttpURLConnection getHttpURLConnection() throws IOException {
        URL url2 = new URL(url);
        HttpURLConnection conn = isHttps(url2) ? getHttpsConn(url2) : getConnImpl(url2);


        // socket setting
        conn.setDoOutput(true);
        conn.setDoInput(true);
        conn.setReadTimeout(timeout);
        conn.setConnectTimeout(timeout);
        conn.setUseCaches(false);

        conn.setRequestProperty("Connection", keepAlive ? "Keep-Alive" : "close");

        return conn;
    }

    private HttpsURLConnection getHttpsConn(URL url) {
        try {
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new SecureRandom());
            HttpsURLConnection conn = (HttpsURLConnection) getConnImpl(url);
            conn.setSSLSocketFactory(sc.getSocketFactory());
            conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
            return conn;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private HttpURLConnection getConnImpl(URL url) throws IOException {
        if (httpProxyAddress == null || httpProxyAddress.trim().length() == 0) {
            return (HttpURLConnection) url.openConnection();
        }

        String address = "";
        int port = 80;

        int pos = httpProxyAddress.indexOf(":");
        if (pos == -1) {
            address = httpProxyAddress;
        } else {
            address = httpProxyAddress.substring(0, pos).trim();
            port = Integer.parseInt(httpProxyAddress.substring(pos + 1).trim());
        }

        InetSocketAddress isa = new InetSocketAddress(address, port);
        Proxy proxy = new Proxy(HTTP, isa);  // http 代理

        HttpURLConnection conn = (HttpURLConnection) url.openConnection(proxy);
        if (httpProxyAuthorization == null || httpProxyAuthorization.trim().length() == 0) {
            return conn;
        }
        conn.setRequestProperty("Proxy-Authorization", httpProxyAuthorization);
        return conn;
    }

    private boolean isHttps(URL url) {
        return url.getProtocol().equalsIgnoreCase("https");
    }

    protected boolean isBlank(String s) {
        return s == null || s.trim().length() == 0;
    }
}